<template>
  <el-date-picker
    v-model="baseData.date"
    class="el-date-picker"
    :size="globalSize"
    :type="newType"
    :unlinkPanels="unlinkPanels"
    :placeholder="placeholder"
    :startPlaceholder="baseData.startPlaceholder || startPlaceholder"
    :endPlaceholder="baseData.endPlaceholder || endPlaceholder"
    rangeSeparator="至"
    :format="format"
    :clearable="clearable"
    :valueFormat="valueFormat"
    :defaultValue="newDefaultValue"
    :shortcuts="newShortcuts"
    :disabled="disabled"
    :disabledDate="disabledDate"
    v-bind="{ teleported, persistent: true, onVisibleChange: onVisibleChangeClick, onChange: changeEvent }"
  ></el-date-picker>
</template>

<script setup lang="ts">
  import type { PropType } from 'vue';
  import { formatDate, getMonday } from '@/utils/time';
  type _$DateType = 'date' | 'daterange' | 'dates' | 'datetime' | 'datetimerange' | 'month' | 'monthrange' | 'week' | 'year' | 0 | 1 | 2;

  type _$Shortcuts = { text: string; value: [Date, Date] }[] | { text: string; value: Date }[];

  const props = defineProps({
    /** 快捷选项 */
    shortcuts: { type: [Array, Boolean] as PropType<_$Shortcuts | boolean>, default: undefined },
    /** 面板的默认值 */
    defaultValue: { type: [Date, Array] as PropType<Date | [Date, Date]>, default: undefined },
    /** 是否将日期选择器的下拉列表插入至 body 元素 */
    teleported: { type: Boolean, default: true },
    /** 是否禁用 */
    disabled: { type: Boolean, default: false },
    /** 组件的尺寸 */
    size: { type: String as PropType<$GlobalSize | ''>, default: '' },
    /** 在范围选择器里取消两个日期面板之间的联动  */
    unlinkPanels: { type: Boolean, default: false },
    /** 默认显示的时间 */
    modelValue: { type: [Date, Array, String] as PropType<string | '' | [string, string]>, default: '' },
    /** 非范围选择时的占位内容 */
    placeholder: { type: String, default: '选择日期' },
    /** 范围选择开始日期的占位内容 */
    startPlaceholder: { type: String, default: '开始日期' },
    /** 范围选择结束日期的占位内容 */
    endPlaceholder: { type: String, default: '结束日期' },
    /** 选择日期的类型 */
    type: { type: [String, Number] as PropType<_$DateType>, default: 'date' },
    /** 显示在输入框中的格式(只用于显示) */
    format: { type: String, default: 'YYYY-MM-DD' },
    /** 绑定值的格式(真实的值) */
    valueFormat: { type: String, default: 'YYYY-MM-DD' },
    /** 限制选择器可选范围的开始日期 (空字符串代表不限制) */
    startDate: { type: [Date, String, Array, Number] as PropType<$FormatDate | ''>, default: '' },
    /** 限制选择器可选范围的结束日期 (空字符串代表不限制) */
    endDate: { type: [Date, String, Array, Number] as PropType<$FormatDate | ''>, default: '' },
    /** 是否显示清除按钮 */
    clearable: { type: Boolean, default: false },
  });

  const emit = defineEmits<{
    (e: 'update:modelValue', val: string | [string, string]): void;
    (e: 'visibleChange', visible: boolean): void;
    (e: 'change', val: string | [string, string]): void;
  }>();

  /** 修改父级组件中孩子组件弹出框状态 (可能有嵌套) */
  const editChildBubbleVisibleFun = inject<false | ((state: boolean) => unknown)>('edit-child-bubble-state', false);

  const globalSize = computed(() => props.size || useGlobalStore().globalSize);

  /** 得到时间类型 */
  const newType = computed(() => (typeof props.type === 'number' ? (props.type === 2 ? 'daterange' : 'date') : props.type));

  /** 是否为时间范围 */
  const isRange = computed(() => ['datetimerange', 'daterange', 'monthrange'].includes(newType.value));

  /** 基础数据 */
  const baseData = shallowReactive({
    oldDate: props.modelValue,
    date: props.modelValue,
    startPlaceholder: props.startPlaceholder,
    endPlaceholder: props.endPlaceholder,
  });

  /** 面板的默认值 */
  const newDefaultValue = computed<Date | [Date, Date]>(() => {
    const date = new Date();
    const aMonthAgo = new Date(new Date().setMonth(date.getMonth() - 1)); // 一月前
    return props.defaultValue ? props.defaultValue : isRange.value ? [aMonthAgo, date] : date;
  });

  /** 快捷选项 */
  const newShortcuts = computed(() => (Array.isArray(props.shortcuts) ? props.shortcuts : props.shortcuts ? getShortcuts(isRange.value) : undefined));

  /** 设置禁用状态,参数为当前日期,要求返回 Boolean */
  function disabledDate(time: Date) {
    const startDate = props.startDate ? formatDate(props.startDate) : null;
    const endDate = props.endDate ? formatDate(props.endDate) : null;
    if (startDate && endDate) {
      return time.getTime() < startDate.getTime() || time.getTime() > endDate.getTime();
    } else if (startDate) {
      return time.getTime() < startDate.getTime();
    } else if (endDate) {
      return time.getTime() > endDate.getTime();
    } else {
      return false;
    }
  }
  watch(
    () => props.modelValue,
    (val) => {
      baseData.date = val;
    }
  );

  watch(
    () => baseData.date,
    (val) => {
      emit('update:modelValue', val);
    }
  );

  /**
   * 监听显示隐藏
   */
  function onVisibleChangeClick(visible: boolean) {
    /** 修改父级组件中孩子组件弹出框状态(用于嵌套弹出框) */
    editChildBubbleVisibleFun && editChildBubbleVisibleFun(visible);
    emit('visibleChange', visible);
  }

  /**
   * 时间发生改变
   */
  function changeEvent(val: string | [string, string]) {
    nextTick(() => {
      emit('change', val);
    });
  }

  /**
   * 得到快捷日期
   */
  function getShortcuts(_isRange: boolean) {
    const date = new Date();
    const yesterday = new Date(date.getTime() - 3600 * 1000 * 24); // 昨天
    const threeDaysAgo = new Date(date.getTime() - 3600 * 1000 * 24 * 3); // 三天前
    const aWeekAgo = new Date(date.getTime() - 3600 * 1000 * 24 * 7); // 一周前
    const aMonthAgo = new Date(new Date().setMonth(date.getMonth() - 1)); // 一月前
    const threeMonthAgo = new Date(new Date().setMonth(date.getMonth() - 3)); // 一月前
    const aYearAgo = new Date(new Date().setFullYear(date.getFullYear() - 1)); // 一年前
    const monday = getMonday(); // 本周一
    const beginMonth = new Date(new Date().setDate(1)); // 本月初
    if (_isRange) {
      // 范围日期快捷选项
      return [
        { text: '今天', value: [date, date] },
        { text: '昨天', value: [yesterday, yesterday] },
        { text: '本周', value: [monday, date] },
        { text: '本月', value: [beginMonth, date] },
        { text: '最近三天', value: [threeDaysAgo, date] },
        { text: '最近一周', value: [aWeekAgo, date] },
        { text: '最近一个月', value: [aMonthAgo, date] },
        { text: '最近三个月', value: [threeMonthAgo, date] },
        { text: '最近一年', value: [aYearAgo, date] },
      ];
    } else {
      // 单个日期快捷选项
      return [
        { text: '今天', value: date },
        { text: '昨天', value: yesterday },
        // { text: '三天前', value: threeDaysAgo },
        { text: '一周前', value: aWeekAgo },
        { text: '一月前', value: aMonthAgo },
        // { text: '三月前', value: threeMonthAgo },
        { text: '一年前', value: aYearAgo },
        { text: '本周一', value: monday },
        { text: '本月初', value: beginMonth },
      ];
    }
  }
</script>
